package com.wsg.dep.util.office;

import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.List;

/**
 * @className: WordGenerator
 * @author: 承泽
 * @date: 2025/3/25 10:03
 * @description: 优化后的Word文档生成器
 */
public class WordGenerator implements ReportGenerator {
    private static final int DEFAULT_FONT_SIZE = 12;
    private static final String TABLE_HEADER_COLOR = "45A4FF";
    private static final String TABLE_BORDER_COLOR = "000000";
    private static final int TABLE_BORDER_SIZE = 4;
    private static final int INDENTATION_FIRST_LINE = 400;
    private static final int SPACING_BEFORE = 200;
    private static final int SPACING_AFTER = 200;

    private XWPFDocument doc;
    private String filePath;
    private String fileName;

    @Override
    public void startCreate(String filePath, String fileName) {
        this.doc = new XWPFDocument();
        this.filePath = filePath;
        this.fileName = fileName;
    }

    @Override
    public void addCatalog(String text, TitleLevel level) {
        XWPFParagraph para = doc.createParagraph();
        para.setIndentationLeft(400 * (level.getLevel() - 1));
        para.setSpacingAfter(100);

        XWPFRun run = para.createRun();
        run.setText(text);
        run.setFontSize(10);
        run.setBold(false);
    }

    @Override
    public void addTitle(String title, TitleLevel level) {
        addTitle(title, level, ParagraphAlignment.LEFT);
    }

    @Override
    public void addTitleCenter(String title, TitleLevel level) {
        addTitle(title, level, ParagraphAlignment.CENTER);
    }

    public void addTitle(String title, TitleLevel level, ParagraphAlignment align) {
        XWPFParagraph para = doc.createParagraph();
        para.setStyle("Heading" + level.getLevel());
        para.setAlignment(align);
        para.setSpacingAfter(SPACING_AFTER);

        XWPFRun run = para.createRun();
        run.setText(title);
        run.setFontSize(level.getSize());
        run.setBold(true);

        setOutlineLevel(para, level.getLevel() - 1);
    }

    @Override
    public void addParagraph(String text, boolean bold, boolean highlight) {
        XWPFParagraph para = doc.createParagraph();
        para.setAlignment(ParagraphAlignment.LEFT);
        para.setIndentationFirstLine(INDENTATION_FIRST_LINE);
        para.setSpacingBefore(SPACING_BEFORE);
        para.setSpacingAfter(SPACING_AFTER);

        XWPFRun run = para.createRun();
        run.setText(text);
        run.setFontSize(DEFAULT_FONT_SIZE);
        run.setBold(bold);

        if (highlight) {
            setHighlight(run);
        }
    }

    @Override
    public void addTable(TableInfo tableInfo) {
        XWPFTable table = doc.createTable(tableInfo.getRowNumb(), tableInfo.getColNumb());
        table.setWidth("100%");

        // 处理表头
        handleTableHead(table, tableInfo.getHead());
        // 处理表体
        handleTableBody(table, tableInfo.getBody());
    }

    private void handleTableHead(XWPFTable table, List<String> head) {
        XWPFTableRow headerRow = table.getRow(0);
        for (int i = 0; i < head.size(); i++) {
            setTableCell(headerRow, i, head.get(i), true);
        }
    }

    private void handleTableBody(XWPFTable table, List<List<String>> body) {
        for (int j = 0; j < body.size(); j++) {
            XWPFTableRow row = table.getRow(j + 1);
            List<String> rows = body.get(j);
            for (int i = 0; i < rows.size(); i++) {
                setTableCell(row, i, rows.get(i), false);
            }
        }
    }

    private void setTableCell(XWPFTableRow row, int col, String text, boolean isHeader) {
        XWPFTableCell cell = row.getCell(col);
        cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);

        XWPFParagraph para = cell.getParagraphs().isEmpty() ? cell.addParagraph() : cell.getParagraphs().get(0);
        para.setAlignment(ParagraphAlignment.CENTER);

        XWPFRun run = para.createRun();
        run.setText(text);
        run.setFontSize(isHeader ? 10 : 8);
        run.setBold(isHeader);

        if (isHeader) {
            cell.setColor(TABLE_HEADER_COLOR);
        }

        setTableBorder(cell);
    }

    private void setTableBorder(XWPFTableCell cell) {
        CTBorder border = createTableBorder();
        CTTcPr tcPr = cell.getCTTc().addNewTcPr();
        CTTcBorders tcBorders = tcPr.addNewTcBorders();
        tcBorders.setBottom(border);
        tcBorders.setTop(border);
        tcBorders.setLeft(border);
        tcBorders.setRight(border);
    }

    private CTBorder createTableBorder() {
        CTBorder border = CTBorder.Factory.newInstance();
        border.setColor(TABLE_BORDER_COLOR);
        border.setSz(BigInteger.valueOf(TABLE_BORDER_SIZE));
        border.setVal(STBorder.SINGLE);
        return border;
    }

    @Override
    public void addPageBreak() {
        XWPFParagraph para = doc.createParagraph();
        para.setPageBreak(true);
    }

    @Override
    public void export() {
        try (FileOutputStream out = new FileOutputStream(new File(filePath + File.separator + fileName))) {
            doc.write(out);
        } catch (IOException e) {
            handleException(e);
        } finally {
            if (doc != null) {
                try {
                    doc.close();
                } catch (IOException e) {
                    handleException(e);
                }
            }
        }
    }

    private void setOutlineLevel(XWPFParagraph para, int level) {
        CTPPr pPr = para.getCTP().isSetPPr() ? para.getCTP().getPPr() : para.getCTP().addNewPPr();
        pPr.addNewOutlineLvl().setVal(BigInteger.valueOf(level));
    }

    private void setHighlight(XWPFRun run) {
        CTRPr rpr = run.getCTR().addNewRPr();
        CTShd shd = rpr.addNewShd();
        shd.setVal(STShd.CLEAR);
        shd.setFill("FFFF00");
    }

    private void handleException(Exception e) {
        // 这里可以添加更复杂的异常处理逻辑，例如日志记录等
        e.printStackTrace();
    }
}